package xyz.xmh.executor;

import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.util.ObjectUtils;
import reactor.core.publisher.Mono;
import xyz.xmh.cache.Cache;
import xyz.xmh.pojo.entity.BaseItem;
import xyz.xmh.pojo.enums.CategoryEnum;
import xyz.xmh.pojo.enums.CheckNameEnum;
import xyz.xmh.pojo.request.file.ListRequest;
import xyz.xmh.pojo.request.file.SearchRequest;
import xyz.xmh.pojo.request.file.UpdateRequest;
import xyz.xmh.pojo.response.file.*;

import java.nio.file.Path;

/**
 * 2021/10/25 16:39 星期一<br/>
 * 缓存执行器
 *
 * @author xuMingHai
 */
public class ReactiveCacheExecutor implements ReactiveExecutor {

    private final Cache cache;

    private final ReactiveExecutor reactiveExecutor;

    public ReactiveCacheExecutor(Cache cache, ReactiveExecutor reactiveExecutor) {
        this.cache = cache;
        this.reactiveExecutor = reactiveExecutor;
    }


    @Override
    public Mono<ResponseEntity<ListResponse>> list() {
        return list(new ListRequest());
    }

    @SuppressWarnings("unchecked")
    @Override
    public Mono<ResponseEntity<ListResponse>> list(ListRequest listRequest) {
        final String key = "reactive_list_" + listRequest.hashCode();
        final Object o = cache.get(key);
        Mono<ResponseEntity<ListResponse>> mono;

        if (ObjectUtils.isEmpty(o)) {
            mono = reactiveExecutor.list(listRequest).cache();
            cache.put(key, mono);
        } else {
            mono = (Mono<ResponseEntity<ListResponse>>) o;
        }

        return mono;
    }

    @Override
    public Mono<ResponseEntity<SearchResponse>> search(String fileName) {
        final SearchRequest searchRequest = new SearchRequest();
        searchRequest.setQuery(fileName);
        return search(searchRequest);
    }

    @Override
    public Mono<ResponseEntity<SearchResponse>> search(String fileName, CategoryEnum categoryEnum) {
        final SearchRequest searchRequest = new SearchRequest();
        searchRequest.setQuery(fileName, categoryEnum);
        return search(searchRequest);
    }

    @SuppressWarnings("unchecked")
    @Override
    public Mono<ResponseEntity<SearchResponse>> search(SearchRequest searchRequest) {
        final String key = "reactive_search_" + searchRequest.hashCode();
        final Object o = cache.get(key);
        Mono<ResponseEntity<SearchResponse>> mono;

        if (ObjectUtils.isEmpty(o)) {
            mono = reactiveExecutor.search(searchRequest).cache();
            cache.put(key, mono);
        } else {
            mono = (Mono<ResponseEntity<SearchResponse>>) o;
        }

        return mono;
    }

    @SuppressWarnings("unchecked")
    @Override
    public Mono<ResponseEntity<BaseItem>> get(String fileId) {
        final String key = "reactive_get_" + fileId;
        final Object o = cache.get(key);
        Mono<ResponseEntity<BaseItem>> mono;

        if (ObjectUtils.isEmpty(o)) {
            mono = reactiveExecutor.get(fileId).cache();
            cache.put(key, mono);
        } else {
            mono = (Mono<ResponseEntity<BaseItem>>) o;
        }

        return mono;
    }

    @Override
    public Mono<ResponseEntity<DownloadUrlResponse>> getDownloadUrl(String fileId) {
        return reactiveExecutor.getDownloadUrl(fileId);
    }

    @Override
    public Mono<ResponseEntity<Resource>> downloadFile(String fileId, HttpHeaders httpHeaders) {
        return reactiveExecutor.downloadFile(fileId, httpHeaders);
    }

    @Override
    public Mono<ResponseEntity<CreateFolderResponse>> createFolder(String parentFileId, String name, CheckNameEnum checkNameEnum) {
        cache.clear();
        return reactiveExecutor.createFolder(parentFileId, name, checkNameEnum);
    }

    @Override
    public Mono<ResponseEntity<CreateFolderResponse>> createFolder(String parentFileId, String name) {
        cache.clear();
        return reactiveExecutor.createFolder(parentFileId, name);
    }

    @Override
    public Mono<ResponseEntity<CreateFolderResponse>> createFolder(String name) {
        cache.clear();
        return reactiveExecutor.createFolder(name);
    }

    @Override
    public Mono<CreateFileResponse> uploadFile(String parentFileId, Path path, CheckNameEnum checkNameEnum) {
        cache.clear();
        return reactiveExecutor.uploadFile(parentFileId, path, checkNameEnum);
    }

    @Override
    public Mono<CreateFileResponse> uploadFile(String parentFileId, Path path) {
        cache.clear();
        return reactiveExecutor.uploadFile(parentFileId, path);
    }

    @Override
    public Mono<CreateFileResponse> uploadFile(Path path) {
        cache.clear();
        return reactiveExecutor.uploadFile(path);
    }

    @Override
    public Mono<ResponseEntity<Void>> trash(String fileId) {
        cache.clear();
        return reactiveExecutor.trash(fileId);
    }

    @Override
    public Mono<ResponseEntity<BaseItem>> update(UpdateRequest updateRequest) {
        cache.clear();
        return reactiveExecutor.update(updateRequest);
    }

    @Override
    public Mono<ResponseEntity<BaseItem>> update(String fileId, String name) {
        cache.clear();
        return reactiveExecutor.update(fileId, name);
    }
}
